#include "StdAfx.h"
#include "Win32Sockets.h"

using namespace Adaptive::Win32;
using namespace Adaptive::Network;
using namespace Adaptive::Network::Sockets;

/*--------------------------------------------------------------------------------
 * Constructor / Dispose / Destructor Methods
 *------------------------------------------------------------------------------*/
#pragma region Constructor / Dispose / Destructor Methods
// Initializes a new instance of the class.
Win32Socket::Win32Socket()
{
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Static Methods / Functions
 *------------------------------------------------------------------------------*/
#pragma region Public Static Methods / Functions
void Win32Socket::InitializeWinsock()
{
	if (lock == NULL)
	{
		lock = new CRITICAL_SECTION();
		InitializeCriticalSection(lock);
	}

	if (wsData == NULL)
	{
		::EnterCriticalSection(lock);

		wsData = new WSADATA();

		WSAStartup(2, wsData);

		::LeaveCriticalSection(lock);
	}
}
void Win32Socket::ShutdownWinsock()
{
	if (lock != NULL)
	{
		::EnterCriticalSection(lock);

		if (wsData != NULL)
		{
			WSACleanup();
			delete(wsData);
			wsData = NULL;
		}
		::LeaveCriticalSection(lock);
		::DeleteCriticalSection(lock);
		lock = NULL;
	}

}
//
SafeSocketHandle^ Win32Socket::Accept(SafeSocketHandle^ listeningSocket)
{
	SOCKET umHandle = (SOCKET)listeningSocket->DangerousGetHandle().ToPointer();
	SOCKET result = 0;
	SafeSocketHandle^ returnValue = nullptr;
	sockaddr* remAddress = new sockaddr();
	int size = sizeof(sockaddr);

	try
	{
		result = ::accept(umHandle, remAddress, &size);
		if (result != SOCKET_ERROR)
		{
			returnValue = gcnew SafeSocketHandle( result );
		}
	}
	catch(...)
	{
	}

	return returnValue;
}
//
SafeSocketHandle^ Win32Socket::Accept(SafeSocketHandle^ listeningSocket, System::Net::SocketAddress^ remoteAddress)
{
	SOCKET umHandle = (SOCKET)listeningSocket->DangerousGetHandle().ToPointer();
	SOCKET result = 0;
	SafeSocketHandle^ returnValue = nullptr;
	sockaddr* remAddress = new sockaddr();
	int size = sizeof(sockaddr);

	try
	{
		result = ::accept(umHandle, remAddress, &size);
		if (result != SOCKET_ERROR)
		{
			remoteAddress = SockAddrToManaged(remAddress);
			returnValue = gcnew SafeSocketHandle( result );
		}
	}
	catch(...)
	{
	}

	delete(remAddress);
	remAddress = NULL;
	return returnValue;
}

bool Win32Socket::Bind(SafeSocketHandle ^listeningSocket, System::Net::IPAddress ^addressToBindTo, short remotePort)
{
	SOCKET			unmanagedSocket = NULL;		//Unmanaged socket handle. 
	sockaddr_in*	socketAddress = NULL;		//Socket address.
	bool			returnValue = false;		//Return value.
	int				result = 0;					//Function call result.

	//Convert the address and handle to unmanaged versions.
	socketAddress = IpAddrToUnManaged(addressToBindTo);
	socketAddress->sin_port = htons(remotePort);
	unmanagedSocket = SocketToUnmanaged(listeningSocket);

	result = ::bind(unmanagedSocket, (sockaddr*)socketAddress, sizeof(sockaddr_in));
	if (result != SOCKET_ERROR)
		returnValue = true;
	else
	{
		throw gcnew SocketException(WSAGetLastError());
	}
	delete(socketAddress);
	socketAddress = NULL;
	return returnValue;

}
bool Win32Socket::Bind(SafeSocketHandle ^listeningSocket, System::Net::SocketAddress ^addressToBindTo)
{
	SOCKET umSocket = NULL;
	sockaddr* unSockAddr = NULL;
	bool returnValue = false;
	int result = 0;

	unSockAddr = SockAddrToUnManaged(addressToBindTo);
	umSocket = SocketToUnmanaged(listeningSocket);

	result = ::bind(umSocket, unSockAddr, sizeof(unSockAddr));
	if (result != SOCKET_ERROR)
		returnValue = true;
	else
	{
		throw gcnew SocketException(WSAGetLastError());
	}
	return returnValue;
}
bool Win32Socket::BindToAll(SafeSocketHandle ^listeningSocket, short remotePort)
{
	return Bind(listeningSocket, IPAddress::Any, remotePort);
}
bool Win32Socket::BindToLoopbackOnly(SafeSocketHandle ^listeningSocket, short remotePort)
{
	return Bind(listeningSocket, IPAddress::Loopback, remotePort);
}

void Win32Socket::CloseSocket(Adaptive::Network::Sockets::SafeSocketHandle ^socketHandle)
{
	if (socketHandle != nullptr)
		socketHandle->Close();
}
void Win32Socket::CloseSocket(IntPtr socketHandle)
{
	if (socketHandle != IntPtr::Zero)
	{
		::closesocket((SOCKET)socketHandle.ToInt32());
	}
}

bool Win32Socket::Connect(Adaptive::Network::Sockets::SafeSocketHandle ^socket, System::Net::IPAddress ^remoteAddress, short remotePort)
{
	SOCKET			socketHandle = NULL;
	sockaddr_in*	sockAddress = NULL;
	int				result = 0;
	bool			returnValue = false;

	//Convert to unmanaged values.
	socketHandle = SocketToUnmanaged(socket);
	sockAddress = IpAddrToUnManaged(remoteAddress);
	sockAddress->sin_port = htons(remotePort);
	sockAddress->sin_family = AF_INET;

	//Perform connection.
	result = ::connect(socketHandle, (sockaddr*)sockAddress, sizeof(sockaddr_in));
	if (result == SOCKET_ERROR)
	{
		throw gcnew SocketException(WSAGetLastError());
	}
	else
		returnValue = true;

	delete(sockAddress);
	sockAddress = NULL;
	socketHandle = NULL;
	return returnValue;
}
bool Win32Socket::Connect(SafeSocketHandle^ socket, SocketAddress^ remoteAddress)
{
	SOCKET		socketHandle = NULL;
	sockaddr*	sockAddress = NULL;
	int			result = 0;
	bool		returnValue = false;

	//Convert to unmanaged values.
	socketHandle = SocketToUnmanaged(socket);
	sockAddress = SockAddrToUnManaged(remoteAddress);
	
	//Perform connection.
	result = ::connect(socketHandle, sockAddress, sizeof(sockAddress));
	if (connect > 0)
		throw gcnew SocketException(WSAGetLastError());
	else
		returnValue = true;

	delete(sockAddress);
	sockAddress=NULL;
	socketHandle = NULL;
	return returnValue;
}
bool Win32Socket::Connect(SafeSocketHandle^ socket, IPEndPoint^ remoteEndPoint)
{
	return Connect(socket, remoteEndPoint->Address, (unsigned short)remoteEndPoint->Port);
}

SocketAddress^ Win32Socket::GetSocketName(SafeSocketHandle^ socket)
{
	SOCKET		handle = SocketToUnmanaged(socket);
	sockaddr*	socketaddress = NULL;
	SocketAddress^ returnValue = nullptr;
	int			size = 0;
	
	socketaddress = new sockaddr();
	size = sizeof(socketaddress);
	::getsockname(handle, socketaddress, &size);
	returnValue = SockAddrToManaged(socketaddress);
	delete(socketaddress);

	return returnValue;
}
generic<typename T>
SocketOptionBase<T>^ Win32Socket::GetSocketOption(Socket^ socket, SocketOptionName name)
{
	ISocketOption^ socketOption = SocketOptionFactory::CreateOptionByName(name);
	BooleanSocketOption^ boolOpt = nullptr;
	DwordSocketOption^	intOpt = nullptr;
	LingerSocketOption^	lingerOpt = nullptr;
	ByteArraySocketOption^ byteOpt = nullptr;

	if (socketOption->GetType() == BooleanSocketOption::typeid)
	{
		boolOpt = (BooleanSocketOption^)socketOption;
		boolOpt->Value = (bool)socket->GetSocketOption(boolOpt->Level, boolOpt->Name);
	}
	if (socketOption->GetType() == DwordSocketOption::typeid)
	{
		intOpt = (DwordSocketOption^)socketOption;
		intOpt->Value = (int)socket->GetSocketOption(intOpt->Level, intOpt->Name);
	}
	if (socketOption->GetType() == ByteArraySocketOption::typeid)
	{
		byteOpt = (ByteArraySocketOption^)socketOption;
		byteOpt->Value = (array<Byte>^)socket->GetSocketOption(byteOpt->Level, byteOpt->Name);
	}
	if (socketOption->GetType() == LingerSocketOption::typeid)
	{
		lingerOpt = (LingerSocketOption^)socketOption;
		lingerOpt->Value = (Linger)socket->GetSocketOption(lingerOpt->Level, lingerOpt->Name);
	}

	return (SocketOptionBase<T>^)socketOption;
}
generic<typename T>
SocketOptionBase<T>^ Win32Socket::GetSocketOption(SafeSocketHandle^ socket, SocketOptionName name)
{
	ISocketOption^ socketOption = SocketOptionFactory::CreateOptionByName(name);
	BooleanSocketOption^ boolOpt = nullptr;
	DwordSocketOption^	intOpt = nullptr;
	LingerSocketOption^	lingerOpt = nullptr;
	ByteArraySocketOption^ byteOpt = nullptr;
	char *buffer = NULL;
	int bufferLength = 0;

	if (socketOption->GetType() == BooleanSocketOption::typeid)
	{
		boolOpt = (BooleanSocketOption^)socketOption;
		::getsockopt((SOCKET)socket->DangerousGetHandle().ToInt32(), (int)boolOpt->Level, (int)boolOpt->Name, buffer, &bufferLength);
		boolOpt->Value =( ((BOOL)buffer[0]) > 0);
	}
	if (socketOption->GetType() == DwordSocketOption::typeid)
	{
		intOpt = (DwordSocketOption^)socketOption;
		::getsockopt((SOCKET)socket->DangerousGetHandle().ToInt32(), (int)boolOpt->Level, (int)boolOpt->Name, buffer, &bufferLength);
		intOpt->Value = *((int*)(buffer));
	}
	if (socketOption->GetType() == ByteArraySocketOption::typeid)
	{
		array<Byte>^ data = nullptr;
		byteOpt = (ByteArraySocketOption^)socketOption;
		::getsockopt((SOCKET)socket->DangerousGetHandle().ToInt32(), (int)boolOpt->Level, (int)boolOpt->Name, buffer, &bufferLength);
		data = gcnew array<Byte>(bufferLength);

		for(int count = 0; count < bufferLength; count++)
			data[count] = (Byte)((BYTE)buffer[count]);

		byteOpt->Value = data;
	}
	if (socketOption->GetType() == LingerSocketOption::typeid)
	{
		LINGER* umLinger = NULL;

		lingerOpt = (LingerSocketOption^)socketOption;
		::getsockopt((SOCKET)socket->DangerousGetHandle().ToInt32(), (int)boolOpt->Level, (int)boolOpt->Name, buffer, &bufferLength);
		umLinger = (LINGER*)buffer;
		lingerOpt->Value.OnOff = umLinger->l_onoff;
		lingerOpt->Value.LingerTime = umLinger->l_linger;
	}

	return (SocketOptionBase<T>^)socketOption;

}
generic<typename T>
void Win32Socket::SetSocketOption(Socket^ socket, SocketOptionBase<T>^ option)
{
}
generic<typename T>
void Win32Socket::SetSocketOption(SafeSocketHandle^ socket, SocketOptionBase<T>^ option)
{
}

#pragma endregion

#pragma region Static Private Methods
sockaddr*		Win32Socket::SockAddrToUnManaged(SocketAddress^ address)
{
	sockaddr* returnValue = NULL;
	int count = 0;

	if (address != nullptr)
	{
		returnValue = new sockaddr();
		returnValue->sa_family = (unsigned short)address->Family;
		for(count = 0; count < 14; count++)
			returnValue->sa_data[count] = address[count];
	}
	return returnValue;
}
SocketAddress^	Win32Socket::SockAddrToManaged(sockaddr* address)
{
	SocketAddress^ returnValue = nullptr;
	int count = 0;

	if (address != NULL)
	{
		returnValue = gcnew SocketAddress((AddressFamily)address->sa_family);
		for(count = 0; count < 14; count++)
			returnValue[count] = address->sa_data[count];
	}
	return returnValue;
}
SOCKET Win32Socket::SocketToUnmanaged(Socket^ originalSocket)
{
	SOCKET returnValue = NULL;

	if (originalSocket != nullptr)
	{
		returnValue = (SOCKET)originalSocket->Handle.ToInt32();
	}
	return returnValue;
}
SOCKET Win32Socket::SocketToUnmanaged(SafeSocketHandle^ originalSocket)
{
	SOCKET returnValue = NULL;

	if (originalSocket != nullptr)
	{
		returnValue = (SOCKET)originalSocket->DangerousGetHandle().ToInt32();
	}
	return returnValue;
}
SafeSocketHandle^ Win32Socket::SocketToManaged(SOCKET originalSocket)
{
	SafeSocketHandle^ returnValue = nullptr;

	if (originalSocket != NULL)
		returnValue = gcnew SafeSocketHandle(originalSocket);

	return returnValue;
}
sockaddr_in*  Win32Socket::IpAddrToUnManaged(IPAddress^ address)
{
	sockaddr_in* returnValue = NULL;
	array<Byte>^ addressBytes = nullptr;

	if (address != nullptr)
	{
		address->GetAddressBytes();
		returnValue = new sockaddr_in();
		returnValue->sin_family = (unsigned short)address->AddressFamily;
		returnValue->sin_port = 0;
		addressBytes = address->GetAddressBytes();

		returnValue->sin_addr.S_un.S_addr = (int)address->Address;
		delete(addressBytes);
	}
	return returnValue;
}
IPAddress^ Win32Socket::IpAddrToManaged(sockaddr_in* address)
{
	IPAddress^ returnValue = nullptr;

	if (address != NULL)
	{
		returnValue = gcnew IPAddress(address->sin_addr.S_un.S_addr);
	}
	return returnValue;
}

int Win32Socket::GetPendingReadByteCount(SafeSocketHandle ^socket)
{
	SOCKET socketHandle = NULL;
	int returnValue = 0;
	u_long byteCount = 0;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->DangerousGetHandle().ToInt32();
		ioctlsocket(socketHandle, FIONREAD, &byteCount);
		returnValue = (int)byteCount;
	}
	return returnValue;
}
int Win32Socket::GetPendingReadByteCount(Socket^ socket)
{
	SOCKET socketHandle = NULL;
	int returnValue = 0;
	u_long byteCount = 0;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->Handle.ToInt32();
		ioctlsocket(socketHandle, FIONREAD, &(byteCount));
		returnValue = (int)byteCount;
	}
	return returnValue;
}

bool Win32Socket::Listen(SafeSocketHandle^ socket, int backLogSize)
{
	SOCKET socketHandle = NULL;
	bool returnValue = false;
	int result = 0;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->DangerousGetHandle().ToInt32();
		result = ::listen(socketHandle, backLogSize);
		returnValue = (result == 0);
	}
	return returnValue;
}
bool Win32Socket::Listen(Socket^ socket, int backLogSize)
{
	SOCKET socketHandle = NULL;
	bool returnValue = false;
	int result = 0;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->Handle.ToInt32();
		result = ::listen(socketHandle, backLogSize);
		returnValue = (result == 0);
	}
	return returnValue;
}
array<Byte>^ Win32Socket::Recieve(SafeSocketHandle^ socket, SocketRecieveFlags recieveFlags)
{
	SOCKET socketHandle = NULL;
	array<Byte>^ returnValue = nullptr;
	BYTE* buffer = NULL;
	int bufferSize = 0;
	int charSize = 0;
	int count = 0;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->DangerousGetHandle().ToInt32();
		buffer = new BYTE[16834];
		bufferSize = 16384;

		charSize = ::recv(socketHandle, (char *)buffer, bufferSize, (int)recieveFlags);
		if (charSize > 0)
		{
			returnValue = gcnew array<Byte>(charSize);
			for(count = 0; count < charSize; count++)
				returnValue[count] = (Byte)buffer[count];

			delete(buffer);
			buffer = NULL;
		}
	}

	return returnValue;
}
array<Byte>^ Win32Socket::Recieve(Socket^ socket, SocketRecieveFlags recieveFlags)
{
	SOCKET socketHandle = NULL;
	array<Byte>^ returnValue = nullptr;
	BYTE* buffer = NULL;
	int bufferSize = 0;
	int charSize = 0;
	int count = 0;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->Handle.ToInt32();
		buffer = new BYTE[16834];
		bufferSize = 16384;

		charSize = ::recv(socketHandle, (char *)buffer, bufferSize, (int)recieveFlags);
		if (charSize > 0)
		{
			returnValue = gcnew array<Byte>(charSize);
			for(count = 0; count < charSize; count++)
				returnValue[count] = (Byte)buffer[count];

			delete(buffer);
			buffer = NULL;
		}
	}

	return returnValue;

}
array<Byte>^ Win32Socket::RecieveFrom(Adaptive::Network::Sockets::SafeSocketHandle ^socket, System::Net::SocketAddress ^recieveFrom, SocketRecieveFlags recieveFlags)
{
	SOCKET socketHandle = NULL;
	array<Byte>^ returnValue = nullptr;
	BYTE* buffer = NULL;
	int bufferSize = 0;
	int charSize = 0;
	int count = 0;
	sockaddr* socketPtr = NULL;
	int addressLength = 0;

	if ((socket != nullptr) && (recieveFrom != nullptr))
	{
		socketPtr = SockAddrToUnManaged(recieveFrom);
		addressLength = sizeof(socketPtr);
		socketHandle = (SOCKET)socket->DangerousGetHandle().ToInt32();
		buffer = new BYTE[16834];
		bufferSize = 16384;

		charSize = ::recvfrom(socketHandle, (char *)buffer, bufferSize, (int)recieveFlags, socketPtr, &addressLength);
		if (charSize > 0)
		{
			returnValue = gcnew array<Byte>(charSize);
			for(count = 0; count < charSize; count++)
				returnValue[count] = (Byte)buffer[count];

			delete(buffer);
			buffer = NULL;
		}
	}

	return returnValue;

}
array<Byte>^ Win32Socket::RecieveFrom(System::Net::Sockets::Socket ^socket, System::Net::IPEndPoint ^recieveFrom, SocketRecieveFlags recieveFlags)
{
	SOCKET socketHandle = NULL;
	array<Byte>^ returnValue = nullptr;
	BYTE* buffer = NULL;
	int bufferSize = 0;
	int charSize = 0;
	int count = 0;
	sockaddr_in* socketPtr = NULL;
	int addressLength = 0;

	if ((socket != nullptr) && (recieveFrom != nullptr))
	{
		socketPtr = new sockaddr_in();
		socketPtr->sin_port = (unsigned short)recieveFrom->Port;
		socketPtr->sin_family = AF_INET;
		socketPtr->sin_addr.S_un.S_addr = (int)recieveFrom->Address->Address;
		addressLength = sizeof(socketPtr);

		socketHandle = (SOCKET)socket->Handle.ToInt32();
		buffer = new BYTE[16834];
		bufferSize = 16384;

		charSize = ::recvfrom(socketHandle, (char *)buffer, bufferSize, (int)recieveFlags, (sockaddr*)socketPtr, &addressLength);
		if (charSize > 0)
		{
			returnValue = gcnew array<Byte>(charSize);
			for(count = 0; count < charSize; count++)
				returnValue[count] = (Byte)buffer[count];

			delete(buffer);
			buffer = NULL;
		}
	}

	return returnValue;

}
array<Byte>^ Win32Socket::RecieveFrom(System::Net::Sockets::Socket ^socket, System::Net::SocketAddress ^recieveFrom, SocketRecieveFlags recieveFlags)
{
	SOCKET socketHandle = NULL;
	array<Byte>^ returnValue = nullptr;
	BYTE* buffer = NULL;
	int bufferSize = 0;
	int charSize = 0;
	int count = 0;
	sockaddr* socketPtr = NULL;
	int addressLength = 0;

	if ((socket != nullptr) && (recieveFrom != nullptr))
	{
		socketPtr = SockAddrToUnManaged(recieveFrom);
		addressLength = sizeof(socketPtr);
		socketHandle = (SOCKET)socket->Handle.ToInt32();
		buffer = new BYTE[16834];
		bufferSize = 16384;

		charSize = ::recvfrom(socketHandle, (char *)buffer, bufferSize, (int)recieveFlags, socketPtr, &addressLength);
		if (charSize > 0)
		{
			returnValue = gcnew array<Byte>(charSize);
			for(count = 0; count < charSize; count++)
				returnValue[count] = (Byte)buffer[count];

			delete(buffer);
			buffer = NULL;
		}
	}

	return returnValue;
}


int Win32Socket::Select(array<SafeSocketHandle^>^ socketsReadList, array<SafeSocketHandle^>^ socketsWriteList, 
					array<SafeSocketHandle^>^ socketsErrorList, int timeout)
{
	FD_SET* readList = NULL;
	FD_SET* writeList = NULL;
	FD_SET* errorList = NULL;
	timeval* timeoutVal = NULL;
	int result = 0;

	readList = ConvertToFdSetArray(socketsReadList);
	writeList = ConvertToFdSetArray(socketsWriteList);
	errorList = ConvertToFdSetArray(socketsErrorList);
	timeoutVal = new timeval();
	timeoutVal->tv_sec = timeout;
	
	result = ::select(0, readList, writeList, errorList, timeoutVal);
	if (result != SOCKET_ERROR)
	{
		if (socketsReadList != nullptr)
			Array::Clear(socketsReadList, 0, socketsReadList->Length);

		if (socketsWriteList != nullptr)
			Array::Clear(socketsWriteList, 0, socketsWriteList->Length);

		if (socketsErrorList != nullptr)
			Array::Clear(socketsErrorList, 0, socketsErrorList->Length);

		socketsReadList = ConvertFromFdSetArray(readList);
		socketsWriteList = ConvertFromFdSetArray(writeList);
		socketsErrorList = ConvertFromFdSetArray(errorList);

		delete(readList);
		delete(writeList);
		delete(errorList);
	}
	else
		throw gcnew SocketException();

	return result;
}
bool Win32Socket::SelectSocketErrors(SafeSocketHandle ^socket)
{
	array<SafeSocketHandle^>^ errorArray = nullptr;
	bool returnValue = false;
	int result = 0;

	errorArray=gcnew array<SafeSocketHandle^>(1);
	errorArray[0] = socket;

	result = Select(nullptr, nullptr, errorArray, 2);

	delete(errorArray);
	errorArray = nullptr;
	returnValue = ((result != SOCKET_ERROR) && (result == 0));
	return returnValue;
}
bool Win32Socket::SelectSocketErrors(System::Net::Sockets::Socket ^socket)
{
	array<SafeSocketHandle^>^ errorArray = nullptr;
	bool returnValue = false;
	int result = 0;

	errorArray=gcnew array<SafeSocketHandle^>(1);
	errorArray[0] = gcnew SafeSocketHandle( (SOCKET)socket->Handle.ToInt32());

	result = Select(nullptr, nullptr, errorArray, 1);

	delete(errorArray);
	errorArray = nullptr;
	returnValue = ((result != SOCKET_ERROR) && (result == 0));
	return returnValue;
}

bool Win32Socket::SelectSocketReadble(SafeSocketHandle ^socket)
{
	array<SafeSocketHandle^>^ readArray = nullptr;
	bool returnValue = false;
	int result = 0;

	readArray=gcnew array<SafeSocketHandle^>(1);
	readArray[0] = socket;

	result = Select(readArray, nullptr, nullptr, 1);

	delete(readArray);
	readArray = nullptr;
	returnValue = ((result != SOCKET_ERROR) && (result == 0));
	return returnValue;
}
bool Win32Socket::SelectSocketReadble(Socket ^socket)
{
	array<SafeSocketHandle^>^ readArray = nullptr;
	bool returnValue = false;
	int result = 0;

	readArray=gcnew array<SafeSocketHandle^>(1);
	readArray[0] = gcnew SafeSocketHandle( (SOCKET)socket->Handle.ToInt32());

	result = Select(readArray, nullptr, nullptr, 1);

	delete(readArray);
	readArray = nullptr;
	returnValue = ((result != SOCKET_ERROR) && (result == 0));
	return returnValue;
}
bool Win32Socket::SelectSocketWriteable(SafeSocketHandle ^socket)
{
	array<SafeSocketHandle^>^ writeArray = nullptr;
	bool returnValue = false;
	int result = 0;

	writeArray=gcnew array<SafeSocketHandle^>(1);
	writeArray[0] = socket;

	result = Select(nullptr, writeArray, nullptr, 1);

	delete(writeArray);
	writeArray = nullptr;
	returnValue = ((result != SOCKET_ERROR) && (result == 0));
	return returnValue;
}
bool Win32Socket::SelectSocketWriteable(Socket ^socket)
{
	array<SafeSocketHandle^>^ writeArray = nullptr;
	bool returnValue = false;
	int result = 0;

	writeArray=gcnew array<SafeSocketHandle^>(1);
	writeArray[0] = gcnew SafeSocketHandle( (SOCKET)socket->Handle.ToInt32());

	result = Select(nullptr, writeArray, nullptr, 1);

	delete(writeArray);
	writeArray = nullptr;
	returnValue = ((result != SOCKET_ERROR) && (result == 0));
	return returnValue;
}
int Win32Socket::Send(Adaptive::Network::Sockets::SafeSocketHandle ^socket, array<Byte>^ dataToSend, SocketSendFlags sendFlags)
{
	SOCKET socketHandle = NULL;
	BYTE* dataBuffer = NULL;
	int dataBufferSize = 0;
	int returnValue = 0;

	if ((dataToSend != nullptr) && (socket != nullptr))
	{
		socketHandle = (SOCKET)socket->DangerousGetHandle().ToInt32();
		dataBufferSize = dataToSend->Length;
		dataBuffer = new BYTE[dataBufferSize];
		for(int count = 0; count < dataBufferSize; count++)
			dataBuffer[count] = (unsigned char)dataToSend[count];

		returnValue = ::send(socketHandle, (const char*)dataBuffer, dataBufferSize, (int)sendFlags);
		delete(dataBuffer);
		dataBuffer = NULL;
	}
	return returnValue;
}
int Win32Socket::Send(System::Net::Sockets::Socket ^socket, cli::array<unsigned char,1> ^dataToSend, SocketSendFlags sendFlags)
{
	SOCKET socketHandle = NULL;
	BYTE* dataBuffer = NULL;
	int dataBufferSize = 0;
	int returnValue = 0;

	if ((dataToSend != nullptr) && (socket != nullptr))
	{
		socketHandle = (SOCKET)socket->Handle.ToInt32();
		dataBufferSize = dataToSend->Length;
		dataBuffer = new BYTE[dataBufferSize];
		for(int count = 0; count < dataBufferSize; count++)
			dataBuffer[count] = (unsigned char)dataToSend[count];

		returnValue = ::send(socketHandle, (const char*)dataBuffer, dataBufferSize, (int)sendFlags);
		delete(dataBuffer);
		dataBuffer = NULL;
	}
	return returnValue;
}
void Win32Socket::ShutdownSocket(Adaptive::Network::Sockets::SafeSocketHandle ^socket, SocketShutdown how)
{
	SOCKET socketHandle = NULL;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->DangerousGetHandle().ToInt32();
		::shutdown(socketHandle, (int)how);
	}
}
void Win32Socket::ShutdownSocket(Socket^ socket, SocketShutdown how)
{
	SOCKET socketHandle = NULL;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->Handle.ToInt32();
		::shutdown(socketHandle, (int)how);
	}
}
FD_SET* Win32Socket::ConvertToFdSetArray(array<SafeSocketHandle^>^ arrayList)
{
	BYTE* baseDataStorage = NULL;
	FD_SET* returnValue = NULL;
	int count = 0;
	int length = 0;

	if ((arrayList != nullptr) && (arrayList->Length > 0))
	{
		length = arrayList->Length;
		//Allocate raw memory.
		baseDataStorage = new BYTE[(length+1) * 4];
		memset(baseDataStorage, 0, length+1);

		//Re-assign pointer.
		returnValue = (FD_SET*)baseDataStorage;
		returnValue->fd_count = length;
		
		//Copy values.
		for(count = 0; count < length; count++)
			returnValue->fd_array[count] = (SOCKET)arrayList[count]->DangerousGetHandle().ToInt32();

	}
	return returnValue;
}
array<SafeSocketHandle^>^ Win32Socket::ConvertFromFdSetArray(FD_SET* unmanagedArray)
{
	array<SafeSocketHandle^>^ returnValue = nullptr;
	int count = 0;
	int length = 0;

	if ((unmanagedArray != NULL) && (unmanagedArray->fd_count > 0))
	{
		length = unmanagedArray->fd_count;
		returnValue = gcnew array<SafeSocketHandle^>(length);

		for (count = 0; count < length; count++)
		{
			returnValue[count] = gcnew SafeSocketHandle(unmanagedArray->fd_array[count]);
		}
	}

	return returnValue;
}

SafeSocketHandle^ Win32Socket::InitSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
{
	SOCKET newSocket = NULL;
	SafeSocketHandle^ returnValue = nullptr;

	newSocket = ::socket((int)addressFamily, (int)socketType, (int)protocolType);
	if (newSocket != NULL)
		returnValue = gcnew SafeSocketHandle( newSocket );

	return returnValue;
}
unsigned int Win32Socket::HostToNetworkOrder(unsigned int original)
{
	return htonl(original);
}
unsigned short Win32Socket::HostToNetworkOrder(unsigned short original)
{
	return htons(original);
}
unsigned int Win32Socket::NetworkOrderToHost(unsigned int original)
{
	return ntohl(original);
}
unsigned short Win32Socket::NetworkOrderToHost(unsigned short original)
{
	return ntohs(original);
}

String^ Win32Socket::InetNtoA(System::Net::IPAddress ^addressValue)
{
	String^ returnValue = nullptr;
	in_addr* ipAddr = NULL;
	array<Byte>^ bytes = nullptr;

	bytes = addressValue->GetAddressBytes();
	ipAddr = new in_addr();
	ipAddr->S_un.S_un_b.s_b1 = bytes[0];
	ipAddr->S_un.S_un_b.s_b2 = bytes[1];
	ipAddr->S_un.S_un_b.s_b3 = bytes[2];
	ipAddr->S_un.S_un_b.s_b4 = bytes[3];

	returnValue = gcnew String( ::inet_ntoa(*ipAddr));
	delete(ipAddr);
	return returnValue;

}
String^ Win32Socket::InetNtoA(System::Net::SocketAddress ^addressValue)
{
	String^ returnValue = nullptr;
	sockaddr_in*	address = NULL;
	in_addr* ipAddr = NULL;

	address = (sockaddr_in*)SockAddrToUnManaged(addressValue);
	ipAddr = new in_addr();
	ipAddr->S_un.S_addr = address->sin_addr.S_un.S_addr;

	returnValue = gcnew String( ::inet_ntoa(*ipAddr));
	delete(ipAddr);
	delete(address);
	return returnValue;
}
String^ Win32Socket::InetNtoA(unsigned int addressValue)
{
	String^ returnValue = nullptr;
	in_addr* ipAddr = NULL;

	ipAddr = new in_addr();
	ipAddr->S_un.S_addr = addressValue;

	returnValue = gcnew String( ::inet_ntoa(*ipAddr));
	delete(ipAddr);
	return returnValue;
}
int Win32Socket::IoCtlSocket(SafeSocketHandle^ socket, int command, short argumentData)
{
	SOCKET socketHandle = NULL;
	int returnValue = 0;
	u_long* dataPointer = NULL;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->DangerousGetHandle().ToInt32();
		dataPointer = (u_long*)&argumentData;
		returnValue = ::ioctlsocket(socketHandle, command, dataPointer);
		dataPointer = NULL;
	}
	return returnValue;
}
int Win32Socket::IoCtlSocket(SafeSocketHandle^ socket, int command, int argumentData)
{
	SOCKET socketHandle = NULL;
	int returnValue = 0;
	u_long* dataPointer = NULL;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->DangerousGetHandle().ToInt32();
		dataPointer = (u_long*)&argumentData;
		returnValue = ::ioctlsocket(socketHandle, command, dataPointer);
		dataPointer = NULL;
	}
	return returnValue;
}
int Win32Socket::IoCtlSocket(SafeSocketHandle^ socket, int command, __int64 argumentData)
{
	SOCKET socketHandle = NULL;
	int returnValue = 0;
	u_long* dataPointer = NULL;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->DangerousGetHandle().ToInt32();
		dataPointer = (u_long*)&argumentData;
		returnValue = ::ioctlsocket(socketHandle, command, dataPointer);
		dataPointer = NULL;
	}
	return returnValue;
}
int Win32Socket::IoCtlSocket(SafeSocketHandle^ socket, int command, String^ argumentData)
{
	SOCKET socketHandle = NULL;
	int returnValue = 0;
	u_long* dataPointer = NULL;
	BYTE* dataContent = NULL;
	int count = 0;

	if (socket != nullptr)
	{
		dataContent = new BYTE[argumentData->Length];
		for(count = 0; count < argumentData->Length; count++)
			dataContent[count] = (unsigned char)argumentData[count];

		socketHandle = (SOCKET)socket->DangerousGetHandle().ToInt32();
		dataPointer = (u_long*)dataContent;
		returnValue = ::ioctlsocket(socketHandle, command, dataPointer);
		dataPointer = NULL;

		delete(dataContent);
	}
	return returnValue;
}
int Win32Socket::IoCtlSocket(SafeSocketHandle^ socket, int command, array<Byte>^ argumentData)
{
	SOCKET socketHandle = NULL;
	int returnValue = 0;
	u_long* dataPointer = NULL;
	BYTE* dataContent = NULL;
	int count = 0;

	if (socket != nullptr)
	{
		dataContent = new BYTE[argumentData->Length];
		for(count = 0; count < argumentData->Length; count++)
			dataContent[count] = (unsigned char)argumentData[count];

		socketHandle = (SOCKET)socket->DangerousGetHandle().ToInt32();
		dataPointer = (u_long*)dataContent;
		returnValue = ::ioctlsocket(socketHandle, command, dataPointer);
		dataPointer = NULL;

		delete(dataContent);
	}
	return returnValue;
}

int Win32Socket::IoCtlSocket(Socket^ socket, int command, short argumentData)
{
	SOCKET socketHandle = NULL;
	int returnValue = 0;
	u_long* dataPointer = NULL;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->Handle.ToInt32();
		dataPointer = (u_long*)&argumentData;
		returnValue = ::ioctlsocket(socketHandle, command, dataPointer);
		dataPointer = NULL;
	}
	return returnValue;
}
int Win32Socket::IoCtlSocket(Socket^ socket, int command, int argumentData)
{
	SOCKET socketHandle = NULL;
	int returnValue = 0;
	u_long* dataPointer = NULL;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->Handle.ToInt32();
		dataPointer = (u_long*)&argumentData;
		returnValue = ::ioctlsocket(socketHandle, command, dataPointer);
		dataPointer = NULL;
	}
	return returnValue;
}
int Win32Socket::IoCtlSocket(Socket^ socket, int command, __int64 argumentData)
{
	SOCKET socketHandle = NULL;
	int returnValue = 0;
	u_long* dataPointer = NULL;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->Handle.ToInt32();
		dataPointer = (u_long*)&argumentData;
		returnValue = ::ioctlsocket(socketHandle, command, dataPointer);
		dataPointer = NULL;
	}
	return returnValue;
}
int Win32Socket::IoCtlSocket(Socket^ socket, int command, String^ argumentData)
{
	SOCKET socketHandle = NULL;
	int returnValue = 0;
	u_long* dataPointer = NULL;
	BYTE* dataContent = NULL;
	int count = 0;

	if (socket != nullptr)
	{
		dataContent = new BYTE[argumentData->Length];
		for(count = 0; count < argumentData->Length; count++)
			dataContent[count] = (unsigned char)argumentData[count];

		socketHandle = (SOCKET)socket->Handle.ToInt32();
		dataPointer = (u_long*)dataContent;
		returnValue = ::ioctlsocket(socketHandle, command, dataPointer);
		dataPointer = NULL;

		delete(dataContent);
	}
	return returnValue;
}
int Win32Socket::IoCtlSocket(Socket^ socket, int command, array<Byte>^ argumentData)
{
	SOCKET socketHandle = NULL;
	int returnValue = 0;
	u_long* dataPointer = NULL;
	BYTE* dataContent = NULL;
	int count = 0;

	if (socket != nullptr)
	{
		dataContent = new BYTE[argumentData->Length];
		for(count = 0; count < argumentData->Length; count++)
			dataContent[count] = (unsigned char)argumentData[count];

		socketHandle = (SOCKET)socket->Handle.ToInt32();
		dataPointer = (u_long*)dataContent;
		returnValue = ::ioctlsocket(socketHandle, command, dataPointer);
		dataPointer = NULL;

		delete(dataContent);
	}
	return returnValue;
}

IPAddress^ Win32Socket::InetAddr(System::String ^original)
{
	CString wideOriginal = original;
	int addressValue = 0;
	int size = original->Length;
	char* destBuffer = new char[size];
	memset(destBuffer, 0, size);

	wcstombs(destBuffer, wideOriginal.GetBuffer(), size);
	addressValue = ::inet_addr(destBuffer);
	delete(destBuffer);

	return gcnew IPAddress((__int64)addressValue);
}

Byte Win32Socket::RecieveByte(SafeSocketHandle^ socket, SocketRecieveFlags recieveFlags)
{
	SOCKET socketHandle = NULL;
	Byte returnValue = 0;
	BYTE* buffer = NULL;
	int bufferSize = 1;
	int charSize = 0;
	int count = 0;

	if (socket != nullptr)
	{
		socketHandle = (SOCKET)socket->DangerousGetHandle().ToInt32();
		buffer = new BYTE[1];
		buffer[0] = 0;
		bufferSize = 1;

		charSize = ::recv(socketHandle, (char *)buffer, bufferSize, (int)recieveFlags);
		if (charSize > 0)
		{
			returnValue = (Byte)buffer[count];
		}
		delete(buffer);
		buffer = NULL;
	}
	return returnValue;
}
IPEndPoint^ Win32Socket::GetRemoteHostAddress(SafeSocketHandle ^socket)
{
	IPEndPoint^ endPoint = nullptr;					// Return value.
	SOCKET socketHandle = NULL;						// Unmanaged socket handle.
	sockaddr_in* address = NULL;					// Address structuer.
	int result = 0;									// Method call result.
	int resultSize = 0;								// Result size.

	if ((socket != nullptr) && (!socket->IsInvalid) && (!socket->IsClosed))
	{
		socketHandle = SocketToUnmanaged(socket);
		try
		{
			address = new sockaddr_in();
			resultSize = sizeof(sockaddr_in);
			result = getpeername(socketHandle, (sockaddr*)address, &resultSize);
			if (result != SOCKET_ERROR)
			{
				endPoint = gcnew IPEndPoint((__int64)address->sin_addr.S_un.S_addr, ntohs(address->sin_port));
				delete(address);
			}
			else
			{
				throw gcnew SocketException(WSAGetLastError());
			}
		}
		catch(Exception^)
		{
			throw gcnew SocketException(WSAGetLastError());
		}
	}
	return endPoint;
}
IPEndPoint^ Win32Socket::GetLocalHostAddress (SafeSocketHandle ^socket)
{
	IPEndPoint^ endPoint = nullptr;					// Return value.
	SOCKET socketHandle = NULL;						// Unmanaged socket handle.
	sockaddr_in* address = NULL;					// Address structuer.
	int result = 0;									// Method call result.
	int resultSize = 0;								// Result size.

	if ((socket != nullptr) && (!socket->IsInvalid) && (!socket->IsClosed))
	{
		socketHandle = SocketToUnmanaged(socket);
		try
		{
			address = new sockaddr_in();
			resultSize = sizeof(sockaddr_in);
			result = getsockname(socketHandle, (sockaddr*)address, &resultSize);
			if (result != SOCKET_ERROR)
			{
				endPoint = gcnew IPEndPoint((__int64)address->sin_addr.S_un.S_addr, ntohs(address->sin_port));
				delete(address);
			}
			else
			{
				throw gcnew SocketException(WSAGetLastError());
			}
		}
		catch(Exception^)
		{
			throw gcnew SocketException(WSAGetLastError());
		}
	}
	return endPoint;
}
#pragma endregion
